/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package bussiness;

import access.FileAccess;
import java.io.*;
import java.net.*;
import java.util.Date;
import javax.swing.JOptionPane;

/**
 *
 * @author L.Duyen
 */
public class ServerListenThread implements Runnable{    
    int port;
    //Socket cliSock;
    BufferedReader bfInp;
    DataOutputStream daOut;
    private WebServerThread serv;
    
    //Phuong thuc khoi tao
    //Cac bien truyen vao gom co httpServer port, socket lang nghe ket noi tu client...
    public ServerListenThread(int port, WebServerThread Server)
    {
        this.port=port;
        //this.cliSock=client;
        this.serv=Server;        
    }
    
    public void ListenRequest()
    {
        ServerSocket ServSock = null;
        try{
            //mo socket lang nghe ket noi
            ServSock = new ServerSocket(port);
            
        }catch(Exception e){
            JOptionPane.showConfirmDialog(null, "Lỗi port!: \n " + e.getMessage());
            //ShowMessageToWindow("\nFatal Error:" + e.getMessage());
            return;
        }
        while(true){
            try{
                //chap nhan ket noi tu client
                Socket cliSock;
                cliSock = ServSock.accept();
                //lay thong tin IP cua client
                InetAddress client = cliSock.getInetAddress();
                //Hien thi thong tin client len server
                //ShowMessageToWindow(client.getHostName() + " connected to server\n");
                //Doc mot yeu cau http tu client vao buffer
                bfInp=new BufferedReader(new InputStreamReader(cliSock.getInputStream()));
                //Chuan bi gui thong diep tra loi cho client
                daOut=new DataOutputStream(cliSock.getOutputStream());
                
                http_handler(bfInp, daOut);
                
            }catch(Exception e){
                ShowMessageToWindow("\nError:"+ e.getMessage());
            }
        }       
        
    }
    
    private void http_handler(BufferedReader input, DataOutputStream output) {
    int method = 0; //1 get, 2 head, 0 not supported
    String http = new String(); //a bunch of strings to hold
    String path = new String(); //the various things, what http v, what path,
    String file = new String(); //what file
    String user_agent = new String(); //what user_agent
    try {
      //This is the two types of request we can handle
      //GET /index.html HTTP/1.0
      //HEAD /index.html HTTP/1.0
      String tmp = input.readLine(); //read from the stream
      String tmp2 = new String(tmp);
      tmp.toUpperCase(); //convert it to uppercase
      if (tmp.startsWith("GET")) { //compare it is it GET
        method = 1;
      } //if we set it to method 1
      if (tmp.startsWith("HEAD")) { //same here is it HEAD
        method = 2;
      } //set method to 2

      if (method == 0) { // not supported
        try {
          output.writeBytes(construct_http_header(501, ""));
          //output.writeBytes("Allow: GET, HEAD")
          output.writeBytes("<h1>501 Not Implemented<h1>");
          output.close();
          return;
        }
        catch (Exception e3) { //if some error happened catch it
          //ShowMessageToWindow("error:" + e3.getMessage());
        } //and display error
      }
      //}

      //tmp contains "GET /index.html HTTP/1.0 ......."
      //find first space
      //find next space
      //copy whats between minus slash, then you get "index.html"
      //it's a bit of dirty code, but bear with me...
      int start = 0;
      int end = 0;
      for (int a = 0; a < tmp2.length(); a++) {
        if (tmp2.charAt(a) == ' ' && start != 0) {
          end = a;
          break;
        }
        if (tmp2.charAt(a) == ' ' && start == 0) {
          start = a;
        }
      }
      path = tmp2.substring(start + 2, end); //fill in the path

      //is path is "", read welcome file
      
      if(path.equals(""))
          path = "www/welcome.html";
      else{
          Filename fn = new Filename(path, '/', '.');
          if(fn.extension() == null){
              //try index.html file
              path += "/index.html";
          }
          /** check file path in mapping file **/
          String strArr[] = path.split("/");
          String str = strArr[0];
          //remove root folder
          String tmpPath = "";
          if(strArr.length >= 2)
            for(int i = 1; i < strArr.length; i++)
                tmpPath += strArr[i];
          //checking
          FileAccess fac = new FileAccess();
          String temp = fac.getFolder("mapping/" + str);
          if(temp == null){ //none folder mapping
              //checking in www folder
              String wwwPath = "www\\" + path;
              if(fac.exists(wwwPath)){
                  //replace / to \\
                  tmpPath = "www/" + path;
                  path = tmpPath.replace("/", "\\");
                  //path = temp + "\\" + path;
              }else{
                    //error 404
                  output.writeBytes(construct_http_header(404, ""));
                  //close the stream
                  String error404 = "<h1>ERROR 404: PAGE NOT FOUND</h1>";
                  output.writeBytes(error404);
                  output.close();
                  return;
              }
          }else{
              //replace / to \\
              path = tmpPath.replace("/", "\\");
              path = temp + "\\" + path;

          }
        }
    }catch (Exception e) {
      ShowMessageToWindow("errorr" + e.getMessage());
    } //catch any exception


    //path do now have the filename to what to the file it wants to open
    //ShowMessageToWindow("\nClient requested:" + new File(path).getAbsolutePath() + "\n");
    FileInputStream requestedfile = null;

    try {
      //NOTE that there are several security consideration when passing
      //the untrusted string "path" to FileInputStream.
      //You can access all files the current user has read access to!!!
      //current user is the user running the javaprogram.
      //you can do this by passing "../" in the url or specify absoulute path
      //or change drive (win)

      //try to open the file,
      requestedfile = new FileInputStream(path);
    }
    catch (Exception e) {
      try {
        //if you could not open the file send a 404
        output.writeBytes(construct_http_header(404, ""));
        //close the stream
        String error404 = "<h1>ERROR 404: PAGE NOT FOUND</h1>";
        output.writeBytes(error404);
        output.close();
        return;
      }
      catch (Exception e2) {}      
    }

    //happy day scenario
    try {      
      //write out the header, 200 ->everything is ok we are all happy.      
      output.writeBytes(construct_http_header(200, path));

      //if it was a HEAD request, we don't print any BODY
      if (method == 1) { //1 is GET 2 is head and skips the body        
          SendDataThread sdt = new SendDataThread();
          //read the file from filestream, and print out through the
          //client-outputstream on a byte per byte[] base.
          sdt.sendData(output, requestedfile);        
      }
    //clean up the files, close open handles
      output.close();
      requestedfile.close();
    }
    catch (Exception e) {}
  }
    
    private String construct_http_header(int return_code, String path) throws FileNotFoundException {
    String s = "HTTP/1.1 ";
    //you probably have seen these if you have been surfing the web a while
    switch (return_code) {
      case 200:
        s = s + "200 OK";
        break;
      case 400:
        s = s + "400 Bad Request";
        break;
      case 403:
        s = s + "403 Forbidden";
        break;
      case 404:
        s = s + "404 Not Found";
        break;
      case 500:
        s = s + "500 Internal Server Error";
        break;
      case 501:
        s = s + "501: Not Implemented";
        break;
    }

    s = s + "\r\n"; //other header fields,
    s = s + "Connection: close\r\n"; //we can't handle persistent connections
    s = s + "Server: java webserver by TranNgocHuyTuong and LeThiDuyen\r\n"; //server name
    if(return_code == 501)
        s += "nAllow: GET, HEAD\r\n";
    Date d = new Date();
    s += "Date: " + d.toGMTString() + "\r\n";

    //Construct the right Content-Type for the header.
    //This is so the browser knows what to do with the
    //file, you may know the browser dosen't look on the file
    //extension, it is the servers job to let the browser know
    //what kind of file is being transmitted. You may have experienced
    //if the server is miss configured it may result in
    //pictures displayed as text!
    if(!path.equals("")){
        s += contentType(path);
        s += contentLength(path);
    }
    
    ////so on and so on......
    s = s + "\r\n"; //this marks the end of the httpheader
    //and the start of the body
    //ok return our newly created header!
    return s;
  }

    private String contentType(String path){
        String str = "";        
        Filename fn = new Filename(path, '\\', '.');
        String fName = fn.filename() + '.' + fn.extension();
        if(path.endsWith(".bmp")){
            str += "Content-Type: image/bmp\r\n";
        }else if(path.endsWith(".gif")){
            str += "Content-Type: image/gif\r\n";
        }else if(path.endsWith(".jp2")){
            str += "Content-Type: image/jp2\r\n";
        }else if(path.endsWith(".jpe")){
            str += "Content-Type: image/jpeg\r\n";
        }else if(path.endsWith(".jpeg")){
            str += "Content-Type: image/jpeg\r\n";
        }else if(path.endsWith(".jpg")){
            str += "Content-Type: image/png\r\n";
        }else if(path.endsWith(".png")){
            str += "Content-Type: image/png\r\n";
        }else if(path.endsWith(".ico")){
            str += "Content-Type: image/x-icon\r\n";
        }else if(path.endsWith(".htm")){
            str += "Content-Type: text/html\r\n";
        }else if(path.endsWith(".html")){
            str += "Content-Type: text/html\r\n";
        }else if(path.endsWith(".js")){
            str += "Content-Type: text/html\r\n";
        }else if(path.endsWith(".css")){
            str += "Content-Type: text/css\r\n";
        }else if(path.endsWith(".text")){
            str += "Content-Type: text/plain\r\n";
        }else if(path.endsWith(".txt")){
            str += "Content-Type: text/plain\r\n";
        }else if (path.endsWith(".aif")) {
            str += "Content-Type: audio/x-aiff\r\n";
            str += "Content-Disposition: attachment; filename=\"" + fName + "\"\r\n";
        }else if(path.endsWith(".aifc")){
            str += "Content-Type: audio/x-aiff\r\n";
            str += "Content-Disposition: attachment; filename=\"" + fName + "\"\r\n";
        }else if(path.endsWith(".aiff")){
            str += "Content-Type: audio/x-aiff\r\n";
            str += "Content-Disposition: attachment; filename=\"" + fName + "\"\r\n";
        }else if(path.endsWith(".mp2")){
            str += "Content-Type: audio/mpeg\r\n";
            str += "Content-Disposition: attachment; filename=\"" + fName + "\"\r\n";
        }else if(path.endsWith(".mp3")){
            str += "Content-Type: audio/mpeg3\r\n";
            str += "Content-Disposition: attachment; filename=\"" + fName + "\"\r\n";
        }else if(path.endsWith(".au")){
            str += "Content-Type: audio/basic\r\n";
            str += "Content-Disposition: attachment; filename=\"" + fName + "\"\r\n";
        }else if(path.endsWith(".avi")){
            str += "Content-Type: video/x-msvideo\r\n";
            str += "Content-Disposition: attachment; filename=\"" + fName + "\"\r\n";
        }else if(path.endsWith(".zip")){
            str += "Content-Type: application/x-zip-compressed\r\n";
            str += "Content-Disposition: attachment; filename=\"" + fName + "\"\r\n";
        }else{
            str += "Content-Disposition: attachment; filename=\"" + fName + "\"\r\n";
        }        

        return str;
    }

    private String contentLength(String path) throws FileNotFoundException{
        FileAccess fac = new FileAccess();
        long size = fac.fileLength(path);
        return "Content-Length: " + size + "\r\n";
    }

 //class phhew caffeine yes please! 

    
    public void ShowMessageToWindow(String s)
    {
        //serv.ShowMessage(s);
    }

    /**
     * @param args the command line arguments
     */
//    public static void main(String[] args) {
//        // TODO code application logic here
//    }

    @Override
    public void run() {
        ListenRequest();
        //http_handler(bfInp, daOut);
        throw new UnsupportedOperationException("Not supported yet.");
    }
}


class Filename {
  private String fullPath;
  private char pathSeparator, extensionSeparator;

  public Filename(String str, char sep, char ext) {
    fullPath = str;
    pathSeparator = sep;
    extensionSeparator = ext;
  }

  public String extension() {
    int dot = fullPath.lastIndexOf(extensionSeparator);
    if(dot == -1) return null;
    return fullPath.substring(dot + 1);
  }

  public String filename() { // gets filename without extension
    int dot = fullPath.lastIndexOf(extensionSeparator);
    int sep = fullPath.lastIndexOf(pathSeparator);
    return fullPath.substring(sep + 1, dot);
  }

  public String path() {
    int sep = fullPath.lastIndexOf(pathSeparator);
    return fullPath.substring(0, sep);
  }
}
